home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK1.toast / Development Kits (Disc 1) / Open Transport / Sample Code / DLPI / OT DLPI Sample1.0B7 / Common Source / EntryPoints.c < prev    next >
Encoding:
Text File  |  1995-06-20  |  33.5 KB  |  1,204 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EntryPoints.c
  3.  
  4.     Contains:    This file contains the structures necessary for the STREAMS environment
  5.                 and also the routines that are not hardware dependent.
  6.  
  7.     Written by:    
  8.  
  9.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.  
  14.     To Do:
  15. */
  16.  
  17.  
  18. //-----------------------------------------------------------------------------------------
  19. // Header files
  20. //-----------------------------------------------------------------------------------------
  21.  
  22. #include <OpenTptModule.h>            // Open Transport files
  23. #include <OpenTptPCISupport.h>        
  24. #include <OpenTptDevLinks.h>
  25. #include <OpenTptLinks.h>
  26. #include <miioccom.h>
  27. #include <stropts.h>
  28. #include <dlpi.h>
  29.  
  30. #include <Kernel.h>                    // System files
  31. #include <DriverServices.h>
  32. #include <Devices.h>
  33. #include <CodeFragments.h>
  34. #include <Interrupts.h>
  35.  
  36. #include "EntryPoints.h"            // our files
  37. #include "DLPIRoutines.h"            
  38. #include "PCIRoutines.h"
  39. #include "HWSpecific.h"
  40.  
  41. //-----------------------------------------------------------------------------------------
  42. // STREAMS Structures
  43. //-----------------------------------------------------------------------------------------
  44.  
  45. static struct module_info moduleInformation = 
  46.     {
  47.     kEnetModuleID,                    // indicates this dlpi is ethernet 
  48.     kModuleDeviceInfoName,
  49.     0,                                // minimum packet data size
  50.     kEnetTSDU,                        // maximum packet data size 
  51.     6000,                            // hi water mark
  52.     5000                            // low water mark 
  53.     };
  54.  
  55. static struct qinit    readSide = 
  56.     {
  57.     putq,
  58.     NULL,
  59.     OpenServiceRoutine,
  60.     CloseServiceRoutine,
  61.     NULL,                            // reserved for future use
  62.     &moduleInformation,
  63.     NULL                            // no module_stat structure
  64.     };
  65.  
  66.  
  67. static struct qinit    writeSide = 
  68.     {
  69.     WritePutRoutine,
  70.     WriteServiceRoutine,
  71.     NULL,                            // no module open needed for write side
  72.     NULL,                            // no module close needed for write side
  73.     NULL,                            // reserved for future use
  74.     &moduleInformation,
  75.     NULL                            // no module_stat structure
  76.     };
  77.  
  78.  
  79. static struct streamtab streamTabInformation = 
  80.     {
  81.     &readSide,
  82.     &writeSide,
  83.     NULL,                            // lower read/write qinit (multiplexors only)
  84.     NULL
  85.     };
  86.  
  87. static struct install_info theInstallInformation =
  88.     {
  89.     &streamTabInformation,             
  90.     kOTModIsDriver,                         // install flags 
  91.     SQLVL_MODULE,                            // Synchronization level 
  92.     0,                                        // Shared writer list buddy 
  93.     0                                        // Flag - set to 0 
  94.     };
  95.  
  96. //-----------------------------------------------------------------------------------------
  97. // Global variable for the entire CFM
  98. //-----------------------------------------------------------------------------------------
  99.  
  100. DLPIPrivateData *gDLPIPrivateData = NULL;    // private data for our dlpi driver         
  101.  
  102. //-----------------------------------------------------------------------------------------
  103. //    Description:
  104. //        This data stucture entry point is exported through the cfm mechanism.  Information
  105. //        about the hardware that this driver works with is located in this structure.
  106. //
  107. //-----------------------------------------------------------------------------------------
  108.  
  109. enum
  110. {
  111.     kFrameFlags = kOTFramingEthernet | kOTFramingEthernetIPX | kOTFraming8022
  112. };
  113.  
  114. DriverDescription TheDriverDescription =
  115. {
  116. // Signature Info
  117.     kTheDescriptionSignature,                    // signature always first
  118.     kInitialDriverDescriptor,                    // version second
  119.  
  120. // Type Info
  121.     kPCIDeviceInfoName,                            // Our name, module info name must match
  122.     1,0,finalStage,0,                            // Major, Minor, Stage, Rev
  123.  
  124. // OS Runtime Info
  125.     kDriverIsUnderExpertControl,                // Runtime Options
  126.     "\penet",                                    // should be kEnetName
  127.     0,0,0,0,0,0,0,0,                            // reserve 8 longs
  128.  
  129. // OS Service Info
  130.     1,                                            // Number of Service Categories                            
  131.     kServiceCategoryOpenTransport,                // We support the 'otan' category
  132.     OTPCIServiceType(kOTEthernetDevice,kFrameFlags,0,1),
  133.     1,0,0,0                                        // Major, Minor, Stage, Rev
  134. };
  135.  
  136.  
  137. //-----------------------------------------------------------------------------------------
  138. //    Description:
  139. //        This routine is used by the driver to validate that our hardware is available.
  140. //        By using the ID we can find out the logical address of the card space (memory or
  141. //        I/O).
  142. //
  143. //        Next we should check if this driver can work with that card.  If the driver can 
  144. //        use the card then return kOTNoError.  The logical address can be used with
  145. //        C pointers (even for I/O space) since GetPCICardBaseAddress returned a logical
  146. //        address.
  147. //
  148. //        Keep in mind that even if the dlpi responds with kOTNoError the user may decide
  149. //        to not use your card...so the card state should be in the same state as when
  150. //        the routine was called.  In other words, turn off the card before you leave
  151. //        this routine and also deallocate any memory that you allocating.  The dlpi
  152. //        may be unloaded from memory so do not expect to have globals between the
  153. //        the ValidateHardware routine and InitStreamModule.
  154. //    
  155. //    Input:
  156. //        theID - node id of the card in the system registry
  157. //
  158. //    Output:
  159. //        kOTNoError if the hardware is available
  160. //        kENXIOErr, if could not obtain card base address or driver does not work with card
  161. //
  162. //-----------------------------------------------------------------------------------------
  163. OTResult ValidateHardware(RegEntryID *theID)
  164. {
  165. OTResult    error = kENXIOErr;        // default error code
  166. UInt32        baseRegAddress, amountAllocated;
  167.     
  168. #if    0
  169. if (GetPCICardBaseAddress(theID,&baseRegAddress, kPCIConfigBase10Offset,&amountAllocated) 
  170.     == kOTNoError)    
  171.     {            // check if our driver works with this card
  172.     if (ABCVendorIsThisOurCard(theID, baseRegAddress))    
  173.         error = kOTNoError;
  174.     }
  175. #endif
  176.  
  177. error = 0;
  178.  
  179. return error;
  180. }
  181.  
  182. //-----------------------------------------------------------------------------------------
  183. //    Description:
  184. //        This routine is required and will only be called once.  The routine must
  185. //        call OTInitModule().  At this point Open Transport has made the decision to
  186. //        use our card for a network connection.  We must save the RegEntryID in case
  187. //        we need it later.  We should get the card assigned address and save
  188. //        it in the dlpi private data area.  The hw must be initialized and memory
  189. //        allocated for dma buffers, install isrs, ....
  190. //
  191. //        Open Transport will start calling our open, put, and service routines after
  192. //        this routine if we return true.
  193. //    
  194. //    Input:
  195. //        theID - node id of the card in the system registry
  196. //
  197. //    Output:
  198. //        true, if initialization was successful
  199. //        false, if initialization failed
  200. //
  201. //-----------------------------------------------------------------------------------------
  202. Boolean    InitStreamModule(RegEntryID *theID)
  203. {
  204. Boolean    initOK;
  205.  
  206. initOK = OTInitModule();
  207. if (initOK)
  208.     {
  209.     ABCVendorInitialize(theID);            // gDLPIPrivateData is set in this routine
  210.     
  211.     if (gDLPIPrivateData == NULL)        // was initialization successful?
  212.         {
  213.         initOK = false;                 // indicate we failed
  214.         OTTerminateModule();            // disconnect ourselves from Open Transport
  215.         }
  216.     }
  217.     
  218. return initOK;
  219. }
  220.  
  221. //-----------------------------------------------------------------------------------------
  222. //    Description:
  223. //        This routine is required and will only be called when the driver is about to be 
  224. //        unloaded.   At this point the driver is going away so we should close down
  225. //        the hardware.  If we get reopened then the InitStreamModule() will get called 
  226. //        again.  The routine must call OTTerminateModule().  
  227. //    
  228. //    Input:
  229. //        NONE
  230. //
  231. //    Output:
  232. //        NONE
  233. //
  234. //-----------------------------------------------------------------------------------------
  235. void TerminateStreamModule(void)
  236. {
  237.  
  238. if (gDLPIPrivateData)
  239.     {
  240.     ABCVendorClose();
  241.     gDLPIPrivateData = NULL;
  242.     }
  243.  
  244. OTTerminateModule();
  245. }
  246.  
  247. //-----------------------------------------------------------------------------------------
  248. //    Description:
  249. //        This is the cfm initialization routine.  It is not required and is almost a 
  250. //        duplication of the InitStreamModule() routine.
  251. //
  252. //    Input:
  253. //        theInitBlock - block containing various cfm information
  254. //
  255. //    Output:
  256. //        NONE
  257. //
  258. //-----------------------------------------------------------------------------------------
  259. OSErr InitCFMRoutine(CFragInitBlock *theInitBlock)
  260. {
  261.  
  262. return kOTNoError;
  263. }
  264.  
  265. //-----------------------------------------------------------------------------------------
  266. //    Description:
  267. //        This is the cfm termination routine.  It is not required and is almost a 
  268. //        duplication of the TerminateStreamModule() routine.
  269. //
  270. //    Input:
  271. //        NONE
  272. //
  273. //    Output:
  274. //        NONE
  275. //
  276. //-----------------------------------------------------------------------------------------
  277. void TerminateCFMRoutine(void)
  278. {
  279.  
  280. }
  281.  
  282. //-----------------------------------------------------------------------------------------
  283. //    Description:
  284. //        This routine returns a pointer to the install_info structure.  The
  285. //        name of the routine must be "GetOTInstallInfo" because OT loads the
  286. //        the function pointer by name.
  287. //
  288. //    Input:
  289. //        NONE
  290. //
  291. //    Output:
  292. //        returns the install_info pointer
  293. //
  294. //-----------------------------------------------------------------------------------------
  295. install_info* GetOTInstallInfo(void)
  296. {
  297.  
  298. return &theInstallInformation;
  299. }
  300.  
  301. //-----------------------------------------------------------------------------------------
  302. //    Description:
  303. //        This routine is called each time a new stream is created.  The
  304. //        stream structure is allocated and then filled in accordingly.  The
  305. //        address of the stream is stored in the dlpi private data and in the read
  306. //        queue data slot.
  307. //
  308. //    Input:
  309. //        q - write queue
  310. //        devp - device number that consists of major and minor
  311. //        genericFlag - not currently used
  312. //        sflag - indicates special open options
  313. //        crp - not currently used
  314. //
  315. //    Output:
  316. //        kOTNoError, if no problem occurred
  317. //        error, if no memory or the client tried to open as a module instead of dlpi
  318. //
  319. //-----------------------------------------------------------------------------------------
  320. int OpenServiceRoutine(queue_t *q, dev_t *devp, int genericflag, int sflag, cred_t *crp)
  321. {
  322. DLPIStream             *theStream;
  323. minor_t             minor_number;
  324.  
  325. if (sflag == MODOPEN)    // this is a dlpi not a module
  326.     return(EINVAL);
  327.  
  328. if (q->q_ptr != NULL)    // this must be a reopen, a stream is already attached
  329.     return kOTNoError;
  330.     
  331.  
  332. if (sflag == CLONEOPEN)     // new streams are opened using the clone
  333.     {        
  334.         
  335.     if ((theStream = OTAllocMem(sizeof(DLPIStream))) == NULL)    // get memory for stream struct        
  336.         return(ENOMEM);
  337.  
  338.     bzero(theStream,sizeof( DLPIStream ));        // set everything to zero
  339.         
  340.     theStream->bufferTimerMsg = mi_timer_alloc(WR(q),sizeof(UInt32));
  341.     if (theStream->bufferTimerMsg == NULL)
  342.         {
  343.         OTFreeMem(theStream);
  344.         return(ENOMEM);
  345.         }    
  346.  
  347.     minor_number = GenerateUniqueMinorDevice();
  348.     *devp = makedevice(getemajor(*devp), minor_number);
  349.  
  350.         // initialize the stream structure
  351.     theStream->readQueue = q;
  352.     theStream->idType = NULL;
  353.     theStream->dlpiState = DL_UNBOUND;
  354.     theStream->streamFlags = NULL;
  355.     theStream->minorDevice = minor_number; 
  356.     
  357.     q->q_ptr = (char *)theStream;
  358.     WR(q)->q_ptr = (char *)theStream;
  359.     
  360.     *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
  361.  
  362.     EnqueueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);
  363.     }
  364.     
  365. return kOTNoError;
  366. }
  367.  
  368. //-----------------------------------------------------------------------------------------
  369. //    Description:
  370. //        This routine closes a stream. All multicast addresses are unregistered and then
  371. //        the memory for the streams structure is deallocated.
  372. //
  373. //    Input:
  374. //        q - write queue
  375. //        dummy1 - not currently used
  376. //        dummy2 - not currently used
  377. //
  378. //    Output:
  379. //        always return kOTNoError
  380. //
  381. //-----------------------------------------------------------------------------------------
  382. int CloseServiceRoutine(queue_t *q, int dummy1, cred_t *dummy2)
  383. {
  384. DLPIStream        *theStream;
  385. mblk_t             *mp;
  386.  
  387. theStream = (DLPIStream *)q->q_ptr;
  388.  
  389. if (theStream->idType == kdlpiBufcallType)            // remove any buf call
  390.     unbufcall(theStream->timeoutID);
  391.  
  392. mi_timer_free(theStream->bufferTimerMsg);    // allocated in open stream for buffer time outs
  393.  
  394.     // disable all multicasts that this stream has registered 
  395. while ((mp = (mblk_t *)DequeueHead( &theStream->multicastQueue, kBothTxRxInterrupts)) != NULL)
  396.     {
  397.     ABCVendorUnregisterMulticast(mp->b_rptr);
  398.     freemsg(mp);
  399.     }
  400.     
  401. q->q_ptr = NULL;            // clear the stream pointers in the read & write queues
  402. (WR(q))->q_ptr = NULL;
  403.  
  404.     // remove this stream from our linked list of stream structures
  405. DequeueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);    
  406. OTFreeMem(theStream);        // and finally free the stream storage 
  407.  
  408. return kOTNoError;
  409. }
  410.  
  411. //-----------------------------------------------------------------------------------------
  412. //    Description:
  413. //        This routine is called when someone wants to put something on our write queue.
  414. //        Somethings are handled immediately are some are put on the write queue and
  415. //        then serviced during the write service routine.  If a message is received that
  416. //        the driver is not expecting then it is dropped on the floor.
  417. //
  418. //    Input:
  419. //        q - the write queue 
  420. //        mp - message that we need to process
  421. //
  422. //    Output:
  423. //        returns true
  424. //
  425. //-----------------------------------------------------------------------------------------
  426. int WritePutRoutine(queue_t *q, mblk_t *mp)
  427. {
  428. union DL_primitives     *dlp;
  429. UInt32                     prim;
  430. DLPIStream                 *theStream;
  431.  
  432. switch (mp->b_datap->db_type) 
  433.     {
  434.     case M_IOCTL:
  435.         IOCtlTheStream(q, mp);
  436.         break;
  437.     case M_FLUSH:
  438.         FlushTheStream(q, mp);
  439.         break;
  440.     case M_PCSIG:    // timer messages come here
  441.         HandleTimerMessages(q, mp);
  442.         break;
  443.     case M_PROTO:
  444.     case M_PCPROTO:
  445.         dlp = (union DL_primitives *)mp->b_rptr;
  446.         prim = dlp->dl_primitive;
  447.         if (prim == DL_UNITDATA_REQ)    // normal transmit packet
  448.             {
  449.             theStream = (DLPIStream *)q->q_ptr;
  450.             DoUnitData(theStream, mp);
  451.             }
  452.         else
  453.             putq(q, mp);        // everything else waits until the service routine
  454.         break;
  455.     case M_DATA:    // raw packet, just send it out with dlpi manipulation
  456.         PreparePacketToBeSent(mp); 
  457.         break;
  458.     case M_COPYIN:
  459.     case M_COPYOUT:
  460.     case M_ERROR:
  461.     case M_HANGUP:
  462.     case M_IOCACK:
  463.     case M_IOCNAK:
  464.     case M_HPDATA:
  465.     case M_STOP:
  466.     case M_START:
  467.     case M_STOPI:
  468.     case M_STARTI:
  469.     case M_READ:
  470.     case M_SETOPTS:
  471.     case M_SIG:
  472.     case M_BREAK:
  473.     case M_DELAY:
  474.     case M_CTL:
  475.     case M_PASSFP:
  476.     case M_RSE:
  477.     default:
  478.         freemsg(mp);
  479.         break;
  480.     }
  481.  
  482. return(kTrue);
  483. }
  484.  
  485. //-----------------------------------------------------------------------------------------
  486. //    Description:
  487. //        This routine handles everything that was deferred (put on the write queue) during
  488. //        the write put routine.  This routine is really just a big switch statement to the
  489. //        different routines that handle each message.  If a message is not supported
  490. //        then an error ack is sent to the client.
  491. //
  492. //    Input:
  493. //        q - the write queue
  494. //
  495. //    Output:
  496. //        returns kOTNoError
  497. //
  498. //-----------------------------------------------------------------------------------------
  499. int WriteServiceRoutine(queue_t *q)
  500. {
  501. mblk_t                     *mp;
  502. DLPIStream                 *theStream;
  503. UInt32                     err, prim;
  504. union DL_primitives     *dlp;
  505. mblk_t                     *next;
  506.  
  507. if ((theStream = (DLPIStream *)q->q_ptr) == NULL || (gDLPIPrivateData == NULL))
  508.     return kOTNoError;
  509.  
  510. while ((mp = getq(q)) != NULL)         // continue retrieving messages until empty
  511.     {
  512.     err = kOTNoError;
  513.     dlp = (union DL_primitives *)mp->b_rptr;
  514.     prim = dlp->dl_primitive;
  515.     switch (prim) 
  516.         {
  517.         case DL_XID_REQ:
  518.             if (DoXID(theStream, mp, 0) == kdlpiRETRY) 
  519.                 {
  520.                 putbq(q, mp);
  521.                 return kOTNoError;
  522.                 }
  523.             break;
  524.         case DL_XID_RES:
  525.             if (DoXID(theStream, mp, 1) == kdlpiRETRY) 
  526.                 {
  527.                 putbq(q, mp);
  528.                 return kOTNoError;
  529.                 }
  530.             break;
  531.         case DL_TEST_REQ:
  532.             if (SendTestPacket(theStream, mp, 0) == kdlpiRETRY) 
  533.                 {
  534.                 putbq(q, mp);
  535.                 return kOTNoError;
  536.                 }
  537.             break;
  538.         case DL_TEST_RES:
  539.             if (SendTestPacket(theStream, mp, 1) == kdlpiRETRY) 
  540.                 {
  541.                 putbq(q, mp);
  542.                 return kOTNoError;
  543.                 }
  544.             break;
  545.         case DL_INFO_REQ:
  546.             if (DoGeneralInfo(theStream) == kdlpiRETRY) 
  547.                 {
  548.                 putbq(q, mp);
  549.                 return kOTNoError;
  550.                 }
  551.             else            
  552.                 freemsg(mp);
  553.             break;
  554.         case DL_SET_PHYS_ADDR_REQ:
  555.             if (DoSetPhysicalAddress(theStream, mp) == kdlpiRETRY) 
  556.                 {
  557.                 putbq(q, mp);
  558.                 return kOTNoError;
  559.                 }
  560.             break;
  561.         case DL_BIND_REQ:
  562.             if (BindTheStream(theStream, mp) == kdlpiRETRY) 
  563.                 {
  564.                 putbq(q, mp);
  565.                 return kOTNoError;
  566.                 }
  567.             break;
  568.         case DL_UNBIND_REQ:
  569.             if (UnBindTheStream(theStream, mp) == kdlpiRETRY) 
  570.                     {
  571.                     putbq(q, mp);
  572.                     return kOTNoError;
  573.                     }
  574.             break;
  575.         case DL_SUBS_BIND_REQ:
  576.             if (SubsBindTheStream(theStream, mp) == kdlpiRETRY) 
  577.                 {
  578.                 putbq(q, mp);
  579.                 return kOTNoError;
  580.                 }
  581.             break;
  582.         case DL_SUBS_UNBIND_REQ:
  583.             if (UnSubsBindTheStream(theStream, mp) == kdlpiRETRY) 
  584.                     {
  585.                     putbq(q, mp);
  586.                     return kOTNoError;
  587.                     }
  588.             break;
  589.         case DL_ENABMULTI_REQ:
  590.             if (DoEnableMulticast(theStream, mp) == kdlpiRETRY) 
  591.                 {
  592.                 putbq(q, mp);
  593.                 return kOTNoError;
  594.                 }
  595.             break;
  596.         case DL_DISABMULTI_REQ:
  597.             if (DoDisableMulticast(theStream, mp) == kdlpiRETRY) 
  598.                 {
  599.                 putbq(q, mp);
  600.                 return kOTNoError;
  601.                 }
  602.             break;
  603.         case DL_PHYS_ADDR_REQ:
  604.             if (DoPhysicalAddressAck(theStream,mp) == kdlpiRETRY) 
  605.                 {
  606.                 putbq(q, mp);
  607.                 return kOTNoError;
  608.                 }
  609.             else
  610.                 freemsg(mp);
  611.             break;
  612. #if    0
  613.         case DL_GET_STATISTICS_REQ:
  614.             if (DoStatisticsAck(theStream,mp) == kdlpiRETRY) 
  615.                 {
  616.                 putbq(q, mp);
  617.                 return kOTNoError;
  618.                 }
  619.             else
  620.                 freemsg(mp);
  621.             break;
  622. #endif
  623.         case DL_ATTACH_REQ:
  624.         case DL_DETACH_REQ:
  625.         case DL_PROMISCON_REQ:
  626.         case DL_PROMISCOFF_REQ:
  627.         case DL_UDQOS_REQ:
  628.         case DL_CONNECT_REQ:
  629.         case DL_CONNECT_RES:
  630.         case DL_TOKEN_REQ:
  631.         case DL_DISCONNECT_REQ:
  632.         case DL_RESET_REQ:
  633.         case DL_RESET_RES:
  634.         case DL_DATA_ACK_REQ:
  635.         case DL_REPLY_REQ:
  636.         case DL_REPLY_UPDATE_REQ:
  637.             err = DL_NOTSUPPORTED; // fall through 
  638.         default:
  639.             if (err == kOTNoError)
  640.                 err = DL_BADPRIM;
  641.             if (DoErrorAck(theStream, mp, prim, err, 0) == kdlpiRETRY) 
  642.                 {
  643.                 putbq(q, mp);
  644.                 return kOTNoError;
  645.                 }
  646.             break;
  647.         }
  648.     }    // while 
  649.  
  650.  
  651. return kOTNoError;
  652. }
  653.  
  654. //-----------------------------------------------------------------------------------------
  655. //    Description:
  656. //        This routine handles all the ioctl calls made to the driver.  Currently only
  657. //        the mentat fast call is handled and the framing type.  
  658. //
  659. //        For the Mentat Fastpath...
  660. //            The dlpi is called and then returns a built header for the current stream.
  661. //
  662. //        For the framing type...
  663. //            If the kOTFraming8022 value is passed in then the general info routine
  664. //            should start returning DL_CSMACD.  If that value is not passed in then
  665. //            the general info routine should return DL_ETHER.
  666. //
  667. //    Input:
  668. //        q - the write queue
  669. //        mp - the message block that contains ioctl parameters
  670. //
  671. //    Output:
  672. //        NONE
  673. //
  674. //-----------------------------------------------------------------------------------------
  675. void IOCtlTheStream(queue_t *q, mblk_t *mp)
  676. {
  677. struct iocblk         *iocPtr = (struct iocblk *)mp->b_rptr;
  678. mblk_t                *headerMP;
  679. long                temp;
  680. DLPIStream             *theStream;
  681.  
  682. iocPtr->ioc_count = 0;
  683. iocPtr->ioc_error = 0;
  684. iocPtr->ioc_rval = 0;
  685.  
  686. switch( iocPtr->ioc_cmd )
  687.     {
  688.     case I_OTSetFramingType:        // toggles what the general info primitive returns
  689.         headerMP = mp->b_cont;    //  for dl_mac_type in dl_info_ack_t structure
  690.         mp->b_cont = NULL;
  691.         if ( headerMP == NULL || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
  692.             {
  693.             if (headerMP)
  694.                 freemsg(headerMP);
  695.             mp->b_datap->db_type = M_IOCNAK;
  696.             break;
  697.             }
  698.         temp = *(long*)headerMP->b_rptr;
  699.         if ( temp == kOTFraming8022 )
  700.             gDLPIPrivateData->privateFlags |= kpfFraming8022;
  701.         else
  702.             gDLPIPrivateData->privateFlags &= ~kpfFraming8022;
  703.         freemsg(headerMP);
  704.         mp->b_datap->db_type = M_IOCACK;
  705.         break;                                
  706.         
  707.     case DL_IOC_HDR_INFO:        // special Mentat call, for fast transmits
  708.         headerMP = mp->b_cont;    // get destination address information
  709.         mp->b_cont = NULL;        // disconnect dest addr mb
  710.  
  711.         headerMP = BuildTxPacketHeader((DLPIStream *)q->q_ptr, headerMP, kTrue);
  712.         
  713.         if (headerMP == NULL)    // could not allocate a message block large enough
  714.             {
  715.             iocPtr->ioc_error    = ENOMEM;
  716.             mp->b_datap->db_type = M_IOCNAK;
  717.             }
  718.         else
  719.             {
  720.             mp->b_cont = headerMP;        // hook mb's back together
  721.             mp->b_datap->db_type = M_IOCACK;
  722.             }
  723.  
  724.         break;                            
  725.         
  726.     case I_OTSetRawMode:            // toggles receive raw packet mode
  727.         theStream = (DLPIStream *)q->q_ptr;
  728.         headerMP = mp->b_cont;
  729.         if ((headerMP == NULL) || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
  730.             {
  731.             if (headerMP)
  732.                 freemsg(headerMP);
  733.             mp->b_datap->db_type = M_IOCNAK;
  734.             break;
  735.             }
  736.         temp = *(long*)headerMP->b_rptr;
  737.         if ( temp == kOTRawRcvOn )
  738.             {
  739.             theStream->streamFlags |= kReadRawPackets;
  740.             mp->b_datap->db_type = M_IOCACK;
  741.             }
  742.         else 
  743.             {
  744.             if ( temp == kOTRawRcvOff )
  745.                 {
  746.                 theStream->streamFlags &= ~kReadRawPackets;
  747.                 mp->b_datap->db_type = M_IOCACK;
  748.                 }
  749.             else    // message value is unkown to us
  750.                 mp->b_datap->db_type = M_IOCNAK;
  751.             }
  752.         break;                                
  753.         
  754.     default:
  755.         mp->b_datap->db_type = M_IOCNAK;
  756.         break;
  757.     }
  758.         
  759. qreply(q, mp);    // send response back up the stream
  760.  
  761. }
  762.  
  763. //-----------------------------------------------------------------------------------------
  764. //    Description:
  765. //        This routine receives the flush call and then it must send it up the read
  766. //        side of the stream.
  767. //
  768. //    Input:
  769. //        q - the write queue
  770. //        mp - the message block that contains the flush parameters
  771. //
  772. //    Output:
  773. //        NONE
  774. //
  775. //-----------------------------------------------------------------------------------------
  776. void FlushTheStream(queue_t *q, mblk_t *mp)
  777. {
  778. UInt8    *rptr = mp->b_rptr;
  779.  
  780. if (*rptr & FLUSHW) 
  781.     {
  782.     flushq(q, FLUSHALL);
  783.     *rptr &= ~FLUSHW;
  784.     }
  785.  
  786. if (*rptr & FLUSHR) 
  787.     {
  788.     flushq(RD(q), FLUSHALL);
  789.     qreply(q, mp);
  790.     }
  791. else
  792.     freemsg(mp);
  793. }
  794.  
  795. //-----------------------------------------------------------------------------------------
  796. //    Description:
  797. //        This routine handles timer messages received on a stream.  The timer message
  798. //        contains an identifier that we define.  Right now the routine only handles
  799. //        one type of timer message.
  800. //
  801. //    Input:
  802. //        writeQueue - write queue which has been given the timer message
  803. //        mp - the message block that contains the flush parameters
  804. //
  805. //    Output:
  806. //        NONE
  807. //
  808. //-----------------------------------------------------------------------------------------
  809. void HandleTimerMessages(queue_t *writeQueue, mblk_t *mp)
  810. {
  811. mblk_t                *headerMP;
  812. DLPIStream             *theStream;
  813. Boolean                isTimerValid;
  814. UInt32                timerMsgType;
  815.  
  816. theStream = (DLPIStream *)writeQueue->q_ptr;
  817.  
  818. isTimerValid = mi_timer_valid(theStream->bufferTimerMsg);
  819.  
  820. if (isTimerValid == kFalse)
  821.     return;
  822.  
  823. timerMsgType = *((UInt32 *)(theStream->bufferTimerMsg->b_rptr));
  824.  
  825. switch(timerMsgType)
  826.     {
  827.     case kEnableQueueTimerMsg:
  828.         *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
  829.         qenable(writeQueue);
  830.         break;
  831.     default:
  832.         break;
  833.     }
  834.  
  835. }
  836.  
  837. //-----------------------------------------------------------------------------------------
  838. //    Description:
  839. //        This routine actually transmits the packet out on the wire.  If the packet
  840. //        is an 802.3 packet then we must fill in the appropriate length (16 bits) in
  841. //        the Ethernet header.  If for some reason the packet cannot be sent when this
  842. //        routine is called then the packet must be kept around until the resources necessary
  843. //        to send the packet are freed up.  One way of doing this might involve creating
  844. //        a linked list of packets needing to be sent.  The resources will probably be
  845. //        freed up during a transmit interrupt.  During the Tx ISR a deferred task is
  846. //        setup to send any packets waiting on the linked list.  
  847. //
  848. //    Input:
  849. //        thePacket - the message block containing the packet to send
  850. //
  851. //    Output:
  852. //        NONE
  853. //
  854. //-----------------------------------------------------------------------------------------
  855. void PreparePacketToBeSent(mblk_t *thePacket)
  856. {
  857. EnetPacketHeader     *enetHeader;
  858. UInt16                len;
  859.  
  860. enetHeader = (EnetPacketHeader *)thePacket->b_rptr;
  861.  
  862. if (enetHeader->fProto == NULL) 
  863.     {
  864.     len = msgdsize(thePacket) - sizeof(EnetPacketHeader);
  865.     enetHeader->fProto = len;
  866.     }
  867.  
  868.     // Fill in the Ethernet source address.
  869. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,enetHeader->fSourceAddr); 
  870.  
  871. thePacket->b_next = NULL;
  872.  
  873. ABCVendorDisableInterrupts(kTxInterrupts);            
  874.  
  875. EnqueueElement(&gDLPIPrivateData->TxPacketQueue, (QElem *)thePacket,kNoInterrupts);        
  876.  
  877. AttemptPacketSend();    // may or may not be able to send the packet
  878.  
  879. ABCVendorEnableInterrupts(kTxInterrupts);            
  880.  
  881. }
  882.  
  883. //-----------------------------------------------------------------------------------------
  884. //    Description:
  885. //        This routine checks the tx packet queue to see if any packets are available 
  886. //        for transmission.  If packets are found then the packet at the head is checked
  887. //        to see if it can fit in the available dma resources. This routine is called by 
  888. //        the normal thread of execution PreparePacketToBeSent and also by TxDTCallback.
  889. //        Both times the tx interrupt enable will be turned off because we want to send
  890. //        out as many packets as possible before we have to service the isr.  Otherwise 
  891. //        we will pop back and forth between this routine and the tx isr which is not as 
  892. //        efficient.
  893. //
  894. //    Input:
  895. //        NONE
  896. //
  897. //    Output:
  898. //        NONE
  899. //
  900. //-----------------------------------------------------------------------------------------
  901. void AttemptPacketSend(void)
  902. {
  903.  
  904. OSErr    error = kOTNoError;        
  905. UInt16    packetSize;
  906. mblk_t    *thePacket;
  907.  
  908. while ((error == kOTNoError) && gDLPIPrivateData->TxPacketQueue.qHead)
  909.     {
  910.     packetSize = msgdsize((mblk_t *)gDLPIPrivateData->TxPacketQueue.qHead);
  911.     error = ABCVendorCheckTransmitterStatus(packetSize);        
  912.     if (error == kOTNoError)        
  913.         {
  914.         thePacket = (mblk_t *)DequeueHead(&gDLPIPrivateData->TxPacketQueue,kNoInterrupts);
  915.         ABCVendorTransmitOnePacket(thePacket,packetSize);    // this routine sends the packet    
  916.         freemsg(thePacket);
  917.         }
  918.     }
  919.  
  920. }
  921.  
  922. //-----------------------------------------------------------------------------------------
  923. //    Description:
  924. //        This routine is called by the deferred task manager.  If for some reason a packet
  925. //        could not be sent in the put routine and was deferred now would be a good time
  926. //        to send it.
  927. //
  928. //    Input:
  929. //        theParam - the refcon value for the call back, not used
  930. //
  931. //    Output:
  932. //        NONE
  933. //
  934. //-----------------------------------------------------------------------------------------
  935.  
  936. pascal void TxDTCallback(void *theParam)
  937. {
  938.  
  939.     // try to send any packets on the wait queue
  940.  
  941. ABCVendorDisableInterrupts(kTxInterrupts);            
  942.  
  943. AttemptPacketSend();    // may or may not be able to send the packet
  944.  
  945. ABCVendorEnableInterrupts(kTxInterrupts);            
  946.  
  947. }
  948.  
  949. //-----------------------------------------------------------------------------------------
  950. //    Description:
  951. //        This routine is called by the deferred task manager.  After the essential work
  952. //        has been done in the ISR then this routine should do the bulk of the work.  
  953. //
  954. //        The isr placed the packet (in the form of a message block) on the rx packet 
  955. //        queue.  It is the responsibility of this routine to dequeue all the packets
  956. //        and pass them on to any clients (streams) that want them.
  957. //
  958. //    Input:
  959. //        theParam - the refcon value for the call back return
  960. //
  961. //    Output:
  962. //        NONE
  963. //
  964. //-----------------------------------------------------------------------------------------
  965.  
  966. pascal void RxDTCallback(void *theParam)
  967. {
  968. mblk_t    *thePacket;
  969.  
  970.  
  971. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kRxInterrupts))
  972.     != NULL)
  973.     FindStreamForReceivedPacket((DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead, thePacket);    
  974.  
  975. }
  976.  
  977. //-----------------------------------------------------------------------------------------
  978. //    Description:
  979. //        This routine is used to enqueue an element onto the head of the list.  
  980. //        An element is just a structure that has as it's first field a link.  The 
  981. //        link field is used to connect structures in a linked list.  Each list contains
  982. //        items of the same type.  The DLPI uses lists to maintain various resources.
  983. //
  984. //    Input:
  985. //        theQHdr - a system type queue header
  986. //        whichIntsOff - the caller determines which interrupts need to be off
  987. //
  988. //    Output:
  989. //        NONE
  990. //
  991. //-----------------------------------------------------------------------------------------
  992. void EnqueueElementAtHead(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  993. {
  994.  
  995. ABCVendorDisableInterrupts(whichIntsOff);        
  996.  
  997. if ((theElem->qLink = theQHdr->qHead) != NULL)    // is the queue nonzero?
  998.     theQHdr->qHead = theElem;
  999. else    // empty list
  1000.     {    
  1001.     theQHdr->qTail = theElem;
  1002.     theElem->qLink = NULL;
  1003.     }
  1004.  
  1005. ABCVendorEnableInterrupts(whichIntsOff);        
  1006.  
  1007. }
  1008.  
  1009. //-----------------------------------------------------------------------------------------
  1010. //    Description:
  1011. //        This routine enqueues an element onto the back of the queue.
  1012. //        An element is just a structure that has as it's first field a link.  The 
  1013. //        link field is used to connect structures in a linked list.  Each list contains
  1014. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1015. //
  1016. //    Input:
  1017. //        theQHdr - a system type queue header
  1018. //        theElem - the element that should be placed on the queue
  1019. //        whichIntsOff - the caller determines which interrupts need to be off
  1020. //
  1021. //    Output:
  1022. //        NONE
  1023. //
  1024. //-----------------------------------------------------------------------------------------
  1025. void EnqueueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  1026. {
  1027.  
  1028. ABCVendorDisableInterrupts(whichIntsOff);        
  1029.  
  1030. if (theQHdr->qHead) 
  1031.     theQHdr->qTail->qLink = theElem;
  1032. else 
  1033.     theQHdr->qHead = theElem;
  1034.     
  1035. theQHdr->qTail = theElem;
  1036. theElem->qLink = NULL;
  1037.  
  1038. ABCVendorEnableInterrupts(whichIntsOff);        
  1039.  
  1040. }
  1041.  
  1042. //-----------------------------------------------------------------------------------------
  1043. //    Description:
  1044. //        This routine dequeues an element.  
  1045. //        An element is just a structure that has as it's first field a link.  The 
  1046. //        link field is used to connect structures in a linked list.  Each list contains
  1047. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1048. //
  1049. //    Input:
  1050. //        theQHdr - a system type queue header
  1051. //        theElem - the element that should be removed from the queue
  1052. //        whichIntsOff - the caller determines which interrupts need to be off
  1053. //
  1054. //    Output:
  1055. //        returns the element if it was found on the queue, NULL if the element was
  1056. //            not on the queue
  1057. //
  1058. //-----------------------------------------------------------------------------------------
  1059.  
  1060. QElem *DequeueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
  1061. {
  1062. QElem    *listWalker,*previousElem;
  1063. Boolean    foundMatch = kFalse;
  1064.  
  1065. ABCVendorDisableInterrupts(whichIntsOff);        
  1066.  
  1067.     // no elements in the list or null element passed in        
  1068. if (((listWalker = theQHdr->qHead) == NULL) || (theElem == NULL))     
  1069.     {
  1070.     ABCVendorEnableInterrupts(whichIntsOff);        
  1071.     return NULL;
  1072.     }
  1073.  
  1074. if (theQHdr->qHead == theElem)            // only 1 element or/and element is the head
  1075.     {
  1076.     DequeueHead(theQHdr,whichIntsOff);        // interrupts will be enabled by enable     
  1077.     return theElem;                            //  routine in DequeueHead
  1078.     }
  1079.  
  1080.  
  1081. previousElem = listWalker;
  1082. while (listWalker && (!(listWalker == theElem)))    // walk thru list till we find a match    
  1083.     {
  1084.     previousElem = listWalker;
  1085.     listWalker = listWalker->qLink;
  1086.     }
  1087.  
  1088. if (listWalker)        // found the element in the list!    
  1089.     {
  1090.     previousElem->qLink = listWalker->qLink;    // disconnect element from the queue
  1091.     if (theElem == theQHdr->qTail)    // was the element the last element on the queue?
  1092.         theQHdr->qTail = previousElem;
  1093.         
  1094.     theElem->qLink = NULL;
  1095.     }
  1096. else
  1097.     theElem = NULL;        // element not in the list
  1098.     
  1099. ABCVendorEnableInterrupts(whichIntsOff);        
  1100.  
  1101. return theElem;
  1102. }
  1103.  
  1104. //-----------------------------------------------------------------------------------------
  1105. //    Description:
  1106. //        This routine dequeues the element at the head of the queue.
  1107. //        An element is just a structure that has as it's first field a link.  The 
  1108. //        link field is used to connect structures in a linked list.  Each list contains
  1109. //        items of the same type.  The DLPI uses lists to maintain various resources.
  1110. //
  1111. //    Input:
  1112. //        theQHdr - a system type queue header
  1113. //        whichIntsOff - the caller determines which interrupts need to be off
  1114. //
  1115. //    Output:
  1116. //        returns the element that was at the head or NULL if the queue was empty
  1117. //
  1118. //-----------------------------------------------------------------------------------------
  1119.  
  1120. QElem *DequeueHead(QHdr *theQHdr, UInt16 whichIntsOff)
  1121. {
  1122. QElem    *theElem;
  1123.  
  1124. ABCVendorDisableInterrupts(whichIntsOff);        
  1125.         
  1126. if (theQHdr->qHead) 
  1127.     {
  1128.     if (theQHdr->qHead == theQHdr->qTail)        // only 1 element in the list
  1129.         theQHdr->qTail = NULL;
  1130.     theElem = theQHdr->qHead;
  1131.     theQHdr->qHead = theElem->qLink;
  1132.     theElem->qLink = NULL;
  1133.     } 
  1134. else 
  1135.     theElem = NULL;
  1136.  
  1137. ABCVendorEnableInterrupts(whichIntsOff);        
  1138.  
  1139. return theElem;
  1140. }
  1141.  
  1142. //-----------------------------------------------------------------------------------------
  1143. //    Description:
  1144. //        This routine generates a unique number for the minor device.  The last used
  1145. //        minor device number is stored in the globals.  The value is incremented by
  1146. //        1 and then each stream is checked to make sure it is not in use.
  1147. //
  1148. //    Input:
  1149. //        NONE
  1150. //
  1151. //    Output:
  1152. //        returns new minor device number for this driver
  1153. //
  1154. //-----------------------------------------------------------------------------------------
  1155.  
  1156. UInt16 GenerateUniqueMinorDevice(void)
  1157. {
  1158. Boolean    found;
  1159.  
  1160.     // start unique number guessing at where we ended last time, we have a possible
  1161.     //  64,000 minor numbers, so if we hit ffff we just start at 0 and continue
  1162.  
  1163. do    {
  1164.     found = CheckThisMinorDevice(++gDLPIPrivateData->currentMinorDeviceNumber);
  1165.     } while(!found);
  1166.  
  1167. return gDLPIPrivateData->currentMinorDeviceNumber;
  1168.  
  1169. }
  1170.  
  1171. //-----------------------------------------------------------------------------------------
  1172. //    Description:
  1173. //        This routine checks a minor device number against all the streams.  If the
  1174. //        minor device number is in use then the routine returns false.
  1175. //
  1176. //    Input:
  1177. //        minorDeviceNumber - the routine checks this device number against device
  1178. //            numbers in existing streams that are attached to this device.
  1179. //
  1180. //    Output:
  1181. //        true, if minorDeviceNumber is not in use by another streams
  1182. //        false, if minorDeviceNumber is in use by another stream
  1183. //
  1184. //-----------------------------------------------------------------------------------------
  1185.  
  1186. Boolean CheckThisMinorDevice(UInt16 minorDeviceNumber)
  1187. {
  1188. mblk_t    *mbWalker;
  1189. Boolean    isUnique = kTrue;
  1190.  
  1191. mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  1192.  
  1193. while (mbWalker && isUnique) 
  1194.     {
  1195.     if (((DLPIStream *)mbWalker)->minorDevice == minorDeviceNumber)
  1196.         isUnique = kFalse;
  1197.     else
  1198.         mbWalker = mbWalker->b_next;
  1199.     }
  1200.     
  1201. return isUnique;
  1202. }
  1203.  
  1204.